#!/usr/bin/env python

# subflip - Prepare subtitle files for non-bidi-aware players.
# Copyright (C) 2006 Noam Raphael < spam.noam at gmail.com >
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

import sys
import re
import codecs

from bidi_algorithm import *
from cdata import cdata

# is_heb gets a string and returns whether it contains Hebrew chars
is_heb = re.compile(u'['+''.join(x for x in cdata
                                 if cdata[x] == 'R') +u']').search
# This regexp searches for something + a line separator. Its sub() method
# is used to flip every line by its own.
# (It will catch the {} at the beginnings of sub format lines, but it doesn't
# matter since they will stay unchanged even if they are considered a part of
# a line.)
lines_re = re.compile(ur'(.+?)((?:\|)|(?:\[br\])|$)')

# This is the character mirroring data for characters in cp1255. To generate
# it, download http://unicode.org/Public/UNIDATA/BidiMirroring.txt and run:
#
# d = {}
# for line in open('BidiMirroring.txt'):
#     line = line.split('#',1)[0].strip()
#     if line:
#         a,b = [int(x.strip(),16) for x in line.split(';')]
#         d[a] = b
# 
# e = {}
# for i in range(256):
#     try:
#         uord = ord(chr(i).decode('cp1255'))
#     except UnicodeDecodeError:
#         pass
#     else:
#         if uord in d:
#             e[uord] = d[uord]
# 
# from pprint import pprint
# pprint(e)

mirror = \
{40: 41,
 41: 40,
 60: 62,
 62: 60,
 91: 93,
 93: 91,
 123: 125,
 125: 123,
 171: 187,
 187: 171,
 8216: 8217,
 8217: 8216,
 8220: 8221,
 8221: 8220,
 8249: 8250,
 8250: 8249}
mirror = dict((unichr(key), unichr(value))
              for key, value in mirror.iteritems())


def visualize_ltr(tokens):
    l = []
    for tok in tokens:
        if tok is OPEN_R:
            l.append(visualize_rtl(tokens))
        elif tok is CLOSE_L:
            break
        else:
            l.append(tok)
    return ''.join(l)

def visualize_rtl(tokens):
    l = []
    for tok in tokens:
        if tok is OPEN_L:
            l.append(visualize_ltr(tokens))
        elif tok is CLOSE_R:
            break
        else:
            l.append(mirror.get(tok, tok))
    return ''.join(reversed(l))

def visualize(s, is_ltr):
    if is_ltr:
        visualize_dir = visualize_ltr
    else:
        visualize_dir = visualize_rtl
        
    return visualize_dir(tag_text(s, is_ltr))
    
def flipline(s):
    if not is_heb(s):
        return s
    return lines_re.sub(lambda m: visualize(m.group(1), True)+m.group(2),
                        s)

def flipfile(source, dest):
    for line in source:
        dest.write(flipline(line))
        
def main():
    if len(sys.argv) > 0 and sys.argv[1] in ('-h', '--help'):
        print '''usage:
%s < source > dest
With no arguments, read input from stdin, write output to stdout.

%s source
With one argument, read a file, write a flipped version.
(".flipped" will be added before the last dot)

%s source dest
With two arguments, read from source, write to dest.

In all those cases, this program takes a subtitles file and arranges
it so that players that aren't bidi-aware will show the letters in
the correct order.

It is currently assumed that the files are cp-1255 (windows) encoded,
and that they were intended to be displayed in a left-to-right context.
''' % (sys.argv[0], sys.argv[0], sys.argv[0])
        sys.exit(1)
        
    if len(sys.argv) == 1:
        source = codecs.EncodedFile(sys.stdin, 'cp1255')
        dest = codecs.EncodedFile(sys.stdout, 'cp1255')
    elif len(sys.argv) == 2:
        sourcefn = sys.argv[1]
        source = codecs.open(sourcefn, 'rb', 'cp1255')
        dotpos = sourcefn.rfind('.')
        if dotpos == -1:
            destfn = sourcefn+'.flipped'
        else:
            destfn = sourcefn[:dotpos]+'.flipped'+sourcefn[dotpos:]
        dest = codecs.open(destfn, 'wb', 'cp1255')
    elif len(sys.argv) == 3:
        source = codecs.open(sys.argv[1], 'rb', 'cp1255')
        dest = codecs.open(sys.argv[2], 'wb', 'cp1255')
        
    flipfile(source, dest)

    source.close()
    dest.close()

if __name__ == '__main__':
    main()
